package com.jingdianjichi.project.infra.basic.es;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.search.sort.ScoreSortBuilder;
import org.springframework.stereotype.Component;
import org.elasticsearch.search.sort.SortOrder;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;

/**
 * ClassName:EsRestClient
 * Package:com.jingdianjichi.subject.infra.basic.es
 * Description:
 *
 * @Author fst
 * @Create 2025/1/5 14:48
 * @Version 1.0
 */

@Component
@Slf4j
public class EsRestClient
{
    public static Map<String, RestHighLevelClient> clientMap=new HashMap<>();


    @Resource
    private EsConfigProperties esConfigProperties;

    private static final RequestOptions COMMON_OPTIONS;

    static
    {
        RequestOptions.Builder builder=RequestOptions.DEFAULT.toBuilder();
        COMMON_OPTIONS=builder.build();
    }


    @PostConstruct
    public void initialize()
    {
        List<EsClusterConfig> esConfigList = esConfigProperties.getEsConfigs();

        esConfigList.forEach(esconfig->
        {
            log.info("initialize.config.name:{},nodes{}",esconfig.getName(),esconfig.getNodes());
            RestHighLevelClient restHighLevelClient = initRestClient(esconfig);
            if(restHighLevelClient!=null) {
                clientMap.put(esconfig.getName(), restHighLevelClient);
            }
            else {
                log.error("config.name:{},node:{}.initError",esconfig.getName(),esconfig.getNodes());
            }
        });
    }

    private RestHighLevelClient initRestClient(EsClusterConfig esClusterConfig)
    {
        String[] ipPortAll = esClusterConfig.getNodes().split(",");

        List<HttpHost> httpHostList =new ArrayList<>(ipPortAll.length);

        for(String ipPort:ipPortAll)
        {
            String[] ipPortInfo = ipPort.split(":");

            if(ipPortInfo.length==2)
            {

                new HttpHost(ipPortInfo[0],Integer.parseInt(ipPortInfo[1]));
                httpHostList.add(new HttpHost(ipPortInfo[0],Integer.parseInt(ipPortInfo[1])));
                log.info("initialize.config.name:{},nodes{}",esClusterConfig.getName(),esClusterConfig.getNodes());
            }
        }
        HttpHost [] httpHosts = new HttpHost[httpHostList.size()];
        httpHostList.toArray(httpHosts);
        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(RestClient.builder(httpHosts));
        return restHighLevelClient;
    }

    private static RestHighLevelClient getClient(String clusterName)
    {
        return clientMap.get(clusterName);
    }
   public static boolean insertDoc(EsIndexInfo esIndexInfo,EsSourceData sourceData)
   {
       try {
           IndexRequest indexRequest = new IndexRequest(esIndexInfo.getIndexName());
           indexRequest.source(sourceData.getData());
           indexRequest.id(sourceData.getDocId());
           getClient(esIndexInfo.getClusterName()).index(indexRequest, COMMON_OPTIONS);
           return true;
       } catch (Exception e) {
           e.printStackTrace();
       }
       return false;
   }


   public static  boolean delete(EsIndexInfo esIndexInfo)
   {
       try {
           DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(esIndexInfo.getClusterName());
           deleteByQueryRequest.setQuery(QueryBuilders.matchAllQuery());
           BulkByScrollResponse Response = getClient(esIndexInfo.getIndexName()).
                   deleteByQuery(deleteByQueryRequest, COMMON_OPTIONS);

           long deleted = Response.getDeleted();
           log.info("delete.index:{},deleted:{}",esIndexInfo.getIndexName(),deleted);

           return deleted>0;

       }catch (Exception e)
       {
           e.printStackTrace();
       }
       return false;
   }

    //删除单个文档
    public static boolean deleteDoc(EsIndexInfo esIndexInfo,String docId)
    {
        try {
            DeleteRequest deleteRequest=new DeleteRequest(esIndexInfo.getIndexName());
            deleteRequest.id(docId);
            getClient(esIndexInfo.getClusterName()).delete(deleteRequest,COMMON_OPTIONS);
            log.info("delete.index:{},docId:{}",esIndexInfo.getIndexName(),docId);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    //查看文档是否存在
    public static boolean isExistDocById(EsIndexInfo esIndexInfo,String docId)
    {
        try {
            GetRequest getRequest=new GetRequest(esIndexInfo.getIndexName());
            getRequest.id(docId);

            if(getClient(esIndexInfo.getClusterName()).exists(getRequest,COMMON_OPTIONS))
            {
                return true;
            }
            log.info("exists.index:{},docId:{}",esIndexInfo.getIndexName(),docId);
        }catch (Exception e)
        {
            e.printStackTrace();
        }
        return false;
    }

    //通过文档id查找文档
    public static Map<String, Object> getDocById(EsIndexInfo esIndexInfo, String docId) {
        try {
            GetRequest getRequest = new GetRequest(esIndexInfo.getIndexName());
            getRequest.id(docId);

            GetResponse getResponse = getClient(esIndexInfo.getClusterName()).get(getRequest, COMMON_OPTIONS);

          return  getResponse.getSourceAsMap();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Map<String,Object> getDocByQuery(EsIndexInfo esIndexInfo,String docId,String[]fields)
    {
        try {
            GetRequest getRequest=new GetRequest(esIndexInfo.getIndexName());

            getRequest.id(docId);

            FetchSourceContext fetchSourceContext=new FetchSourceContext(true,fields,null);

            getRequest.fetchSourceContext(fetchSourceContext);

            GetResponse getResponse=getClient(esIndexInfo.getClusterName()).get(getRequest,COMMON_OPTIONS);

            return getResponse.getSourceAsMap();

        }catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    public static SearchResponse searchWithTermQuery(EsIndexInfo esIndexInfo, EsSearchRequest esSearchRequest)
    {
        try {
            BoolQueryBuilder bq = esSearchRequest.getBq();
            String[] fields = esSearchRequest.getFields();
            int from = esSearchRequest.getFrom();
            int size=esSearchRequest.getSize();
            Long minutes=esSearchRequest.getMinutes();
            Boolean needScroll=esSearchRequest.getNeedScroll();
            String sortName=esSearchRequest.getSortName();
            SortOrder sortOrder=esSearchRequest.getSortOrder();

            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(bq);
            searchSourceBuilder.fetchSource(fields,null).from(from).size(size);

            if(Objects.nonNull(esSearchRequest.getHighlightBuilder()))
            {
               searchSourceBuilder.highlighter(esSearchRequest.getHighlightBuilder());
            }

            if(!(sortName==null||sortName.equals("")))
            {
                searchSourceBuilder.sort(sortName);
            }

            searchSourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));

            SearchRequest searchRequest = new SearchRequest();

            searchRequest.searchType(SearchType.DEFAULT);
            searchRequest.indices(esIndexInfo.getIndexName());
            searchRequest.source(searchSourceBuilder);
            if(needScroll)
            {
                searchRequest.scroll(TimeValue.timeValueMinutes(minutes));
            }

            RestHighLevelClient client = getClient(esIndexInfo.getClusterName());
            return client.search(searchRequest, COMMON_OPTIONS);
        }catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    //更新文档
    public static boolean updateDoc(EsIndexInfo esIndexInfo,EsSourceData sourceData) {
        try {
            UpdateRequest updateRequest = new UpdateRequest();
            updateRequest.index(esIndexInfo.getIndexName());
            updateRequest.id(sourceData.getDocId());
            updateRequest.doc(sourceData.getData());

            getClient(esIndexInfo.getClusterName()).update(updateRequest, COMMON_OPTIONS);

            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static boolean batchUpdateDoc(EsIndexInfo esIndexInfo,List<EsSourceData> esSourceDataList)
    {
        try {
            BulkRequest bulkRequest=new BulkRequest();
            for (EsSourceData esSourceData : esSourceDataList)
            {
                String docId=esSourceData.getDocId();
                if(!(docId==null||docId.equals(""))) {

                    UpdateRequest updateRequest = new UpdateRequest();

                    updateRequest.index(esIndexInfo.getIndexName());

                    updateRequest.id(esSourceData.getDocId());

                    updateRequest.doc(esSourceData.getData());

                    bulkRequest.add(updateRequest);
                }

                BulkResponse bulk = getClient(esIndexInfo.getClusterName()).
                        bulk(bulkRequest, COMMON_OPTIONS);

                if(bulk.hasFailures())
                {
                    return false;
                }
            }
        }catch (Exception e)
        {
            e.printStackTrace();
        }
        return true;
    }
}
